package Estructuras.Arboles;

/**
 *
 * @author humbertino
 */
public class AVL<type> {

    String impresor="";
    pointerAVL<type> root= null;
    boolean permiso=true;
    public void add(String nick,type nuevo)
    {
        if(existe(nick,root)!=true)
        {
            pointerAVL<type> in = new pointerAVL<type>();
            //System.out.println("nuevo: "+nick);
            in.setNick(nick);
            in.setDatos(nuevo);
            root=insertar(root,in);
        }else{
            System.out.println("Usuario Existente.");
        }
    }

    pointerAVL<type> insertar(pointerAVL<type> raiz, pointerAVL<type> entrante)
    {
        pointerAVL<type> N1;
        pointerAVL<type> nuevo=entrante;
        if(vacio(raiz))
        {
            raiz=entrante;
            System.out.println("Usuario Ingresado: "+nuevo.getNick());
            permiso=true;
        }else{
            if(nuevo.getNick().compareTo(raiz.getNick())==-1)
            {
                raiz.setIzquierda(insertar(raiz.getIzquierda(),nuevo));
                if(permiso)
                {
                    switch(raiz.getFactorEquilibrio())
                    {
                        case 1: {raiz.setFactorEquilibrio(0);permiso=false;} break;
                        case 0: {raiz.setFactorEquilibrio(-1);} break;
                        case -1: {
                            N1=raiz.getIzquierda();
                            if(N1.getFactorEquilibrio()==-1)
                            {
                                raiz = RotacionIzquierdaIzquierda(raiz,N1);
                            }else{
                                raiz = RotacionIzquierdaDerecha(raiz,N1);
                            }
                            permiso =false;
                        }break;
                    }
                }
            }else{
                if(nuevo.getNick().compareTo(raiz.getNick())==1)
                {
                    raiz.setDerecha(insertar(raiz.getDerecha(),nuevo));
                    if(permiso)
                    {
                        switch(raiz.getFactorEquilibrio())
                        {
                            case -1: {raiz.setFactorEquilibrio(0); permiso=false;} break;
                            case 0: {raiz.setFactorEquilibrio(1);} break;
                            case 1: {
                                N1=raiz.getDerecha();
						if (N1.getFactorEquilibrio()==1){
							raiz = RotacionDerechaDerecha(raiz,N1);
						}
						else{
                                                        raiz = RotacionDerechaIzquierda(raiz,N1);
						}
						permiso = false;
                            }break;
                        }
                    }
                }else{System.out.println("Usuario Existente."); permiso = false;}
            }
        }
        return raiz;
    }

    pointerAVL<type> RotacionDerechaDerecha(pointerAVL<type> N, pointerAVL<type> N1){
                N.setDerecha(N1.getIzquierda());
		N1.setIzquierda(N);
		if (N1.getFactorEquilibrio()==1) {
			N.setFactorEquilibrio(0);
			N1.setFactorEquilibrio(0);
		}
		else{
			N.setFactorEquilibrio(1);
			N1.setFactorEquilibrio(-1);
		}
		N= N1;
		return N;
	}

	pointerAVL<type> RotacionDerechaIzquierda(pointerAVL<type> N, pointerAVL<type> N1){
		pointerAVL<type> N2;
		N2 = N1.getIzquierda();
                N.setDerecha(N2.getIzquierda());
		N2.setIzquierda(N);
                N1.setIzquierda(N2.getDerecha());
		N2.setDerecha(N1);
		if (N2.getFactorEquilibrio()==1){
			N.setFactorEquilibrio(-1);
		}
		else{
			N.setFactorEquilibrio(0);
		}
		if (N2.getFactorEquilibrio()==-1){
			N1.setFactorEquilibrio(1);}
		else{
			N1.setFactorEquilibrio(0);}
		N2.setFactorEquilibrio(0);
		N=N2;
		return N;
	}

	pointerAVL<type> RotacionIzquierdaIzquierda(pointerAVL<type> N, pointerAVL<type> N1){
                N.setIzquierda(N1.getDerecha());
		N1.setDerecha(N);
		if (N1.getFactorEquilibrio()==-1){
			N.setFactorEquilibrio(0);
			N1.setFactorEquilibrio(0);
		}
		else{
			N.setFactorEquilibrio(-1);
			N1.setFactorEquilibrio(1);
		}
		N=N1;
		return N;
	}

	pointerAVL<type> RotacionIzquierdaDerecha(pointerAVL<type> N, pointerAVL<type> N1){
		pointerAVL<type> N2;
		N2=N1.getDerecha();
                N.setIzquierda(N2.getDerecha());
		N2.setDerecha(N);
                N1.setDerecha(N2.getIzquierda());
		N2.setIzquierda(N1);
		if (N2.getFactorEquilibrio()==1)
			N1.setFactorEquilibrio(-1);
		else
			N1.setFactorEquilibrio(0);
		if (N2.getFactorEquilibrio()==-1)
			N.setFactorEquilibrio(1);
		else
			N.setFactorEquilibrio(0);
		N2.setFactorEquilibrio(0);
		N=N2;
		return N;
	}

    boolean vacio(pointerAVL<type> R){
		return (R == null);
	}
    
    public boolean existe(String nick, pointerAVL<type> finder)
    {
        pointerAVL<type> aux = finder;
        boolean existe=false;
        while(aux!=null)
        {
             if(nick.equals(aux.getNick())==true)
             {
                existe=true;
                aux=null;
             }else{
                 if(nick.compareTo(aux.getNick())==1)
                 {
                     aux=aux.getDerecha();
                 }else{
                     aux=aux.getIzquierda();
                     if(aux==null)
                     {
                         existe=false;
                     }
                 }
             }
        }
        return existe;
    }

    public void postOrdenAVL (pointerAVL<type> Nodo){
		if (Nodo == null)
			return;
		else{
			postOrdenAVL (Nodo.getIzquierda());
			postOrdenAVL (Nodo.getDerecha());
                        System.out.print(Nodo.getNick()+",");
		}
	}

    public void inOrdenAVL (pointerAVL<type> Nodo){
		if (Nodo == null)
			return;
		else{
			inOrdenAVL (Nodo.getIzquierda());
                        System.out.print(Nodo.getNick()+",");
			inOrdenAVL (Nodo.getDerecha());
		}
	}

    public void preOrdenAVL (pointerAVL<type> Nodo)
    {
        if (Nodo == null)
			return;
		else{
                        System.out.print(Nodo.getNick()+",");
			preOrdenAVL (Nodo.getIzquierda());
                        preOrdenAVL (Nodo.getDerecha());
		}
    }
    
    public int size(pointerAVL F)
    {
        int cont=0;
        if(F==null)
        {
         cont = cont;
        }else{
            cont = cont + 1 + size(F.getIzquierda()) + size(F.getDerecha());
        }
        return cont;
    }

    public pointerAVL<type> getRoot() {
        return root;
    }

    public void setRoot(pointerAVL<type> root) {
        this.root = root;
    }
    
    public int Altura(pointerAVL<type> raiz)
    {
        if (raiz == null)
		return 0;
		else
		return	1 + Math.max(Altura(raiz.getIzquierda()), Altura(raiz.getDerecha()));
    }
    
}
